package com.small.flowable.modules.app.controllers;


import com.alibaba.nacos.api.utils.StringUtils;
import com.common.basis.oauth.AuUser;
import com.common.basis.result.Result;
import com.common.basis.result.ResultSet;
import com.small.flowable.modules.app.dao.entities.ActivityVo;
import com.small.flowable.modules.app.dao.entities.EndProcessVo;
import com.small.flowable.modules.app.dao.entities.GoBackVo;
import com.small.flowable.modules.app.dao.entities.TaskCompleteVo;
import com.small.flowable.modules.app.dto.rsp.TaskRsp;
import com.small.flowable.modules.app.services.TaskInstanceService;
import com.small.flowable.modules.modeler.services.MyRemoteService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.flowable.bpmn.model.BpmnModel;
import org.flowable.bpmn.model.GraphicInfo;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.UserTask;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.form.api.FormInfo;
import org.flowable.identitylink.api.IdentityLink;
import org.flowable.identitylink.api.IdentityLinkType;
import org.flowable.image.impl.DefaultProcessDiagramGenerator;
import org.flowable.task.api.Task;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;


/**
 * 任务实例
 *
 * @author wangguochao
 */
@RestController
@AllArgsConstructor
@RequestMapping("task")
@Slf4j
public class TaskInstanceController {
    private final TaskInstanceService taskInstanceService;
    private final TaskService taskService;
    /**
     * 运行时服务
     */
    private final RuntimeService runtimeService;
    /**
     * 仓库服务
     */
    private final RepositoryService repositoryService;
    private final MyRemoteService myRemoteService;


    /**
     * 完成任务
     **/
    @PutMapping("runtime/complete")
    public Result<?> completeTask(@RequestBody TaskCompleteVo param) {
        taskService.complete(param.getTaskId());
        return ResultSet.success();
    }

    /**
     * 完成任务-表单
     **/
    @PutMapping("runtime/complete/form")
    public Result<?> completeTaskAndForm(@RequestBody TaskCompleteVo param) {
        taskService.complete(param.getTaskId(), param.getVariables());
        return ResultSet.success();
    }

    /**
     * 获取任务列表
     */
    @GetMapping("runtime/list")
    public Result<List<TaskRsp>> getTaskRspList(String assignee) {
        return ResultSet.go(taskInstanceService.getTaskList(assignee));
    }

    /**
     * 获取指定流程-正在执行任务列表
     */
    @GetMapping("runtime/{processInstanceId}/list")
    public Result<List<TaskRsp>> getListByProcessInstanceId(@PathVariable String processInstanceId) {
        return ResultSet.go(taskInstanceService.getTaskListByProcessInstanceId(processInstanceId));
    }


    /**
     * 查询流程图
     */
    @RequestMapping(value = "processDiagram")
    public void genProcessDiagram(HttpServletResponse httpServletResponse, String processId) throws Exception {
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(processId).singleResult();
        //流程走完的不显示图
        if (pi == null) {
            return;
        }
        List<Execution> executions = runtimeService
                .createExecutionQuery()
                .processInstanceId(pi.getId())
                .list();
        //得到正在执行的Activity的Id
        List<String> activityIds = new ArrayList<>();
        List<String> flows = new ArrayList<>();
        for (Execution exe : executions) {
            List<String> ids = runtimeService.getActiveActivityIds(exe.getId());
            activityIds.addAll(ids);
        }
        //获取流程图
        BpmnModel bpmnModel = repositoryService.getBpmnModel(pi.getProcessDefinitionId());
        DefaultProcessDiagramGenerator diagramGenerator = new DefaultProcessDiagramGenerator();
        byte[] buf = new byte[1024];
        int length = 0;
        try (InputStream in = diagramGenerator
                .generateDiagram(
                        bpmnModel,
                        "bmp",
                        activityIds,
                        flows,
                        "宋体",
                        "宋体",
                        "宋体",
                        null,
                        1.0,
                        true);
             OutputStream out = httpServletResponse.getOutputStream()) {
            while ((length = in.read(buf)) != -1) {
                out.write(buf, 0, length);
            }
        }
    }

    /**
     * 获取节点测试
     */
    @GetMapping("graphicInfo")
    public Result<ArrayList<Object>> graphicInfo(@RequestParam String processDefinitionId) {
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        // 获得所有流程定的节点信息
        List<UserTask> userTasks = new ArrayList<>();
        List<Process> processes = bpmnModel.getProcesses();
        processes.forEach(process -> {
            List<UserTask> userTask = process.findFlowElementsOfType(UserTask.class);
            userTasks.addAll(userTask);
        });
        ArrayList<Object> list = new ArrayList<>();
        for (UserTask userTask : userTasks) {
            GraphicInfo graphicInfo = bpmnModel.getGraphicInfo(userTask.getId());
            ActivityVo vo = new ActivityVo();
            vo.setCandidateUsers(userTask.getCandidateUsers());
            vo.setCandidateGroups(userTask.getCandidateGroups());
            vo.setId(userTask.getId());
            vo.setX(graphicInfo.getX());
            vo.setY(graphicInfo.getY());
            vo.setAssignee(userTask.getAssignee());
            vo.setWidth(graphicInfo.getWidth());
            vo.setHeight(graphicInfo.getHeight());
            vo.setCandidateUsers(userTask.getCandidateUsers());
            vo.setDocumentation(userTask.getDocumentation());
            vo.setName(userTask.getName());
            vo.setTaskDefKey(userTask.getId());
            list.add(vo);
        }
        return ResultSet.go(list);

    }

    /**
     * 任务节点情况
     *
     * @param taskDefinitionKey 任务ID
     * @param processInstanceId 任务ID
     */
    @GetMapping("getTask")
    public Result<TaskRsp> getTask(@RequestParam String taskDefinitionKey,
                                   @RequestParam String processInstanceId) {
        Task task = taskService.createTaskQuery()
                .taskDefinitionKey(taskDefinitionKey)
                .processInstanceId(processInstanceId)
                .singleResult();
        //获取接口带出来带候选人与候选组信息
        List<String> originalCandidateUsers = new ArrayList<>();
        List<String> originalCandidateGroups = new ArrayList<>();
        //获取实时候选信息做同步操作
        List<IdentityLink> identityLinks = taskService.getIdentityLinksForTask(task.getId());
        for (IdentityLink identityLink : identityLinks) {
            if (!IdentityLinkType.CANDIDATE.equalsIgnoreCase(identityLink.getType())) {
                continue;
            }
            //不存在候选信息则同步添加
            if (!StringUtils.isEmpty(identityLink.getUserId()) && !originalCandidateUsers.contains(identityLink.getUserId())) {
                originalCandidateUsers.add(identityLink.getUserId());
            } else if (!StringUtils.isEmpty(identityLink.getGroupId()) && !originalCandidateGroups.contains(identityLink.getGroupId())) {
                originalCandidateGroups.add(identityLink.getGroupId());
            }
        }
        TaskRsp taskRsp = taskInstanceService.trainToTaskRsp(task);
        if (!originalCandidateUsers.isEmpty()) {
            Result<List<AuUser>> byIds = myRemoteService.findByIds(originalCandidateUsers);
            if (byIds.getStatus() == 200) {
                List<AuUser> data = byIds.getData();
                taskRsp.setOriginalCandidateUsers(data);
            }
        }
        //TODO 用户组
        taskRsp.setOriginalCandidateGroups(originalCandidateGroups);
        return ResultSet.go(taskRsp);
    }

    /**
     * 表单-获取表单
     *
     * @param taskId 任务ID
     * @return 表单
     */
    @GetMapping("getTaskFormModel")
    public Result<FormInfo> getTaskFormModel(String taskId) {
        FormInfo formInfo = taskService.getTaskFormModel(taskId);
        return ResultSet.go(formInfo);
    }

    /**
     * 表单-开始表单
     *
     * @param processDefinitionId 流程定义ID
     * @param processInstanceId   流程实例ID
     */
    @GetMapping("getStartFormModel")
    public Result<FormInfo> getStartFormModel(String processDefinitionId, String processInstanceId) {
        FormInfo formInfo = runtimeService.getStartFormModel(processDefinitionId, processInstanceId);
        return ResultSet.go(formInfo);
    }

    /**
     * 结束流程
     */
    @PutMapping("endProcess")
    public Result<?> endProcess(@RequestBody EndProcessVo param) {
        runtimeService.deleteProcessInstance(param.getProcessInstanceId(), param.getDeleteReason());
        return ResultSet.success();
    }

    /**
     * 退回
     */
    @PutMapping("goBack")
    public Result<?> goBack(@RequestBody @Validated GoBackVo param) {
        List<String> currentActivityIds = taskService.createTaskQuery()
                .processInstanceId(param.getProcessInstanceId())
                .active()
                .list()
                .stream()
                .map(Task::getTaskDefinitionKey)
                .collect(Collectors.toList());
        runtimeService.createChangeActivityStateBuilder()
                .processInstanceId(param.getProcessInstanceId())
                .moveActivityIdsToSingleActivityId(currentActivityIds, param.getNewActivityId())
                .changeState();
        return ResultSet.success();
    }
}
